<template>
  <canvas ref="canvasRulerRef" class="ruler-canvas"></canvas>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'

const props = defineProps({
  direction: { type: String as () => 'horizontal' | 'vertical', default: 'horizontal' },
  tickColor: { type: String, default: '#ccc' },
  textColor: { type: String, default: '#999' },
  unitSize: { type: Number, default: 100 },
  subTickCount: { type: Number, default: 5 },
  offset: { type: Number, default: 0 },
  valueScale: { type: Number, default: 100 },
  textOffsetX: { type: Number, default: 4 },
  textOffsetY: { type: Number, default: 10 }
})

const canvasRulerRef = ref<HTMLCanvasElement | null>(null)
let resizeObserver: ResizeObserver | null = null

const drawRuler = () => {
  const canvas = canvasRulerRef.value
  if (!canvas) return
  const ctx = canvas.getContext('2d')
  if (!ctx) return

  const dpr = window.devicePixelRatio || 1
  const rect = canvas.getBoundingClientRect()

  canvas.width = rect.width * dpr
  canvas.height = rect.height * dpr
  ctx.scale(dpr, dpr)

  const width = rect.width
  const height = rect.height

  ctx.clearRect(0, 0, width, height)

  const {
    direction,
    unitSize,
    offset,
    subTickCount,
    valueScale,
    tickColor,
    textColor,
    textOffsetX,
    textOffsetY
  } = props

  const step = unitSize / subTickCount
  const startSub = ((-offset % step) + step) % step
  const firstSubIndex = Math.floor((offset + startSub) / step)

  ctx.strokeStyle = tickColor
  ctx.fillStyle = textColor
  ctx.font = '10px sans-serif'
  ctx.textAlign = 'left'
  ctx.textBaseline = 'top'

  if (direction === 'horizontal') {
    // 小刻度
    for (let i = 0; i <= Math.ceil(width / step); i++) {
      const x = startSub + i * step
      const globalIndex = firstSubIndex + i
      if (globalIndex % subTickCount === 0) continue
      ctx.beginPath()
      ctx.moveTo(x, 0)
      ctx.lineTo(x, height * 0.5)
      ctx.stroke()
    }

    // 主刻度
    const start = ((-offset % unitSize) + unitSize) % unitSize
    const startIndex = Math.floor((offset + start) / unitSize)

    for (let x = start, i = 0; x <= width; x += unitSize, i++) {
      const value = (startIndex + i) * valueScale
      ctx.beginPath()
      ctx.moveTo(x, 0)
      ctx.lineTo(x, height)
      ctx.stroke()
      ctx.fillText(`${value}`, x + textOffsetX, textOffsetY)
    }
  } else if (direction === 'vertical') {
    // 小刻度
    for (let i = 0; i <= Math.ceil(height / step); i++) {
      const y = startSub + i * step
      const globalIndex = firstSubIndex + i
      if (globalIndex % subTickCount === 0) continue
      ctx.beginPath()
      ctx.moveTo(0, y)
      ctx.lineTo(width * 0.5, y)
      ctx.stroke()
    }

    // 主刻度
    const start = ((-offset % unitSize) + unitSize) % unitSize
    const startIndex = Math.floor((offset + start) / unitSize)

    for (let y = start, i = 0; y <= height; y += unitSize, i++) {
      const value = (startIndex + i) * valueScale
      ctx.beginPath()
      ctx.moveTo(0, y)
      ctx.lineTo(width, y)
      ctx.stroke()
      ctx.save()
      ctx.translate(textOffsetX, y + textOffsetY)
      ctx.rotate(-Math.PI / 2) // 逆时针旋转90度（文字朝下）
      ctx.fillText(`${value}`, 0, 0)
      ctx.restore()
    }
  }
}

onMounted(() => {
  nextTick(() => {
    drawRuler()
  })

  resizeObserver = new ResizeObserver(() => {
    drawRuler()
  })

  if (canvasRulerRef.value) {
    resizeObserver.observe(canvasRulerRef.value)
  }
})

onBeforeUnmount(() => {
  if (resizeObserver && canvasRulerRef.value) {
    resizeObserver.unobserve(canvasRulerRef.value)
  }
})

watch(
  () => [
    props.direction,
    props.unitSize,
    props.subTickCount,
    props.offset,
    props.tickColor,
    props.textColor,
    props.valueScale,
    props.textOffsetX,
    props.textOffsetY
  ],
  drawRuler
)
</script>

<style scoped>
.ruler-canvas {
  width: 100%;
  height: 100%;
  display: block;
  background-color: transparent;
  pointer-events: none;
}
</style>
